package zlib

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"unicode"
)

// reflectFinalValue 获取反射的最终值.
func reflectFinalValue(r reflect.Value) (reflect.Value, bool) {
	var isPtr bool
	// 如果是指针,则获取其所指向的元素
	if r.Kind() == reflect.Ptr {
		r = r.Elem()
		isPtr = true
	}
	return r, isPtr
}

// reflectFinalType 获取反射的最终类型.
func reflectFinalType(r reflect.Type) (reflect.Type, bool) {
	var isPtr bool
	// 如果是指针,则获取其所指向的元素
	if r.Kind() == reflect.Ptr {
		r = r.Elem()
		isPtr = true
	}
	return r, isPtr
}

// reflectTypesMap 递归获取反射字段类型Map.
func reflectTypesMap(r reflect.Type, res map[string]reflect.Type) {
	for i := 0; i < r.NumField(); i++ {
		field := r.Field(i)
		if field.Anonymous { //匿名字段
			subTyp := r.Field(i).Type
			reflectTypesMap(subTyp, res)
		} else if field.PkgPath == "" { //公开字段
			res[field.Name] = field.Type
		}
	}
}

// reflect2Itf 将反射值转为接口(原值)
func reflect2Itf(r reflect.Value) (res interface{}) {
	switch r.Kind() {
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64:
		res = r.Int()
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64:
		res = r.Uint()
	case reflect.Float32, reflect.Float64:
		res = r.Float()
	case reflect.String:
		res = r.String()
	case reflect.Bool:
		res = r.Bool()
	default:
		if r.CanInterface() {
			res = r.Interface()
		} else {
			res = r
		}
	}

	return
}

// structVal 获取结构体的反射值.
func structVal(obj interface{}) (reflect.Value, error) {
	v := reflect.ValueOf(obj)

	for v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	if v.Kind() != reflect.Struct {
		return v, errors.New("[structVal]`obj type must be struct; but : " + v.Kind().String())
	}

	return v, nil
}

// structFields 获取结构体的字段切片;all是否包含所有字段(包括未导出的).
func structFields(obj interface{}, all bool) ([]reflect.StructField, error) {
	v, e := structVal(obj)
	if e != nil {
		return nil, e
	}

	var fs []reflect.StructField
	var t = v.Type()
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		// 不能访问未导出的字段
		if !all && field.PkgPath != "" {
			continue
		}

		fs = append(fs, field)
	}

	return fs, nil
}

// compareConditionMap 比对数组是否匹配条件.condition为条件字典,arr为要比对的数据(字典/结构体).
func compareConditionMap(condition map[string]interface{}, arr interface{}) (res interface{}) {
	val := reflect.ValueOf(arr)
	conNum := len(condition)
	if conNum > 0 {
		chkNum := 0

		switch val.Kind() {
		case reflect.Map:
			if conNum > 0 {
				for _, k := range val.MapKeys() {
					if condVal, ok := condition[k.String()]; ok && reflect.DeepEqual(val.MapIndex(k).Interface(), condVal) {
						chkNum++
					}
				}
			}
		case reflect.Struct:
			var field reflect.Value
			for k, v := range condition {
				field = val.FieldByName(k)

				if field.IsValid() && field.CanInterface() && reflect.DeepEqual(field.Interface(), v) {
					chkNum++
				}
			}
		default:
			panic("[compareConditionMap]`arr type must be map|struct; but : " + val.Kind().String())
		}

		if chkNum == conNum {
			res = arr
		}
	}

	return
}

// getTrimMask 获取要修剪的字符串集合,masks为要屏蔽的字符切片.
func getTrimMask(masks []string) string {
	var str string
	if len(masks) == 0 {
		str = blankChars
	} else {
		str = strings.Join(masks, "")
	}
	return str
}

// GetFieldValue 获取(字典/结构体的)字段值;fieldName为字段名,大小写敏感.
func GetFieldValue(arr interface{}, fieldName string) (res interface{}, err error) {
	val := reflect.ValueOf(arr)
	switch val.Kind() {
	case reflect.Map:
		for _, subKey := range val.MapKeys() {
			if fmt.Sprintf("%s", subKey) == fieldName {
				res = val.MapIndex(subKey).Interface()
				break
			}
		}
	case reflect.Struct:
		field := val.FieldByName(fieldName)
		if !field.IsValid() || !field.CanInterface() {
			break
		}
		res = field.Interface()
	default:
		err = errors.New("[GetFieldValue]`arr type must be map|struct; but : " + val.Kind().String())
	}

	return
}

// isCaseConnector 是否字符转换连接符.
func isCaseConnector(r rune) bool {
	return r == '-' || r == '_' || unicode.IsSpace(r)
}

func invokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
	fv := functionValue(fn)
	params := make([]reflect.Value, len(args))
	for i, item := range args {
		params[i] = reflect.ValueOf(item)
	}
	return fv.Call(params)
}

func unsafeInvokeFunc(fn interface{}, args ...interface{}) []reflect.Value {
	fv := reflect.ValueOf(fn)
	params := make([]reflect.Value, len(args))
	for i, item := range args {
		params[i] = reflect.ValueOf(item)
	}
	return fv.Call(params)
}

func functionValue(function interface{}) reflect.Value {
	v := reflect.ValueOf(function)
	if v.Kind() != reflect.Func {
		panic(fmt.Sprintf("Invalid function type, value of type %T", function))
	}
	return v
}

func mustBeFunction(function interface{}) {
	v := reflect.ValueOf(function)
	if v.Kind() != reflect.Func {
		panic(fmt.Sprintf("Invalid function type, value of type %T", function))
	}
}
